package com.cskaoyan.javase.oop2._0encapsulate._0Introduction;

/**
 * @description: 面向对象的三大特征之一:封装
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

/**
 * > 封装（encapsulate）是一种信息隐藏技术，依赖于访问权限控制符实现
 * - 所谓封装即是，隐藏对象中属性和一些实现细节，仅对外提供公共的访问方法
 *   - 广义的说类也是一种封装，指将数据和基于数据的操作封装在一起
 *
 *   - 狭义的封装则是指借助访问权限控制符，将数据和数据操作保护在内部的一种技术
 *     - 此时系统的其他部分只有通过在数据外面的被授权的操作才能够进行交互
 * - 封装的目的是将类的使用者和设计者分开
 * - 在面向对象的编程中，用类来封装相关的数据和方法，保证了数据的安全和系统的严密性
 *
 *
 * 思考：我们之前定义的类中，都没有关注访问权限控制符，会有什么问题？
 *      1.如果不希望被外界访问,不做访问控制是不行的
 *      2.之间的成员变量的访问和赋值都是通过对象名点的形式,但是这种形式有缺点:
 *          a.访问和赋值明明是两种操作却使用了一种方式
 *          b.无论是访问还是赋值都是不可控的
 *
 *为了解决以上问题,可以考虑做以下改进:
 *      1.既然不希望在外界被访问,那就直接私有化它
 *      2.做完操作1后,外界就完全访问不到了,这肯定也不行.所以要根据情况提供访问和赋值的方式:
 *          访问的方法称之为get/getter方法,方法名应该命名为: getXxxx,其中Xxx是成员变量的名字
 *          赋值的方法称之为set/setter方法,方法名应该命名为: setXxxx,其中Xxx是成员变量的名字
 *
 * 综上,以后我们在开发中,绝大多数情况下,成员变量都应该是私有的(这是规则,大家都这么写,很少有不私有化的成员变量)
 *      如果外界想要访问和赋值,再提供get/set方法
 * 当然在上课时,私有化提供get/set方法毕竟还是麻烦一点,为了上课方便,很少这么做
 *
 * 私有化成员变量然后提供方法访问和赋值、封装设计的好处:
 *      1.私有化成员变量，然后根据需要提供get、set方法。可以完全控制成员变量的访问
 *      2.get、set方法将成员变量的赋值和访问分开了，并且变得可控了
 *
 *
 * 注意：
 *      静态成员变量，基本和普通成员变量没有区别，但是要注意get、set方法也要是静态的
 *      当然类中的静态成员变量很多不是私有的,直接通过类名访问
 *
 *
 */
public class Demo {
    public static void main(String[] args) {
        /*Student s = new Student("梅赛德斯", 18, 100);
        System.out.println(s.getName());
        s.setName("李浩");
        System.out.println(s.getName());*/

        Student s = new Student("张三", 100);
        System.out.println(s.getAge());
        s.setAge(18);
        System.out.println(s.getAge());
    }
}

class Student {
    private String name;
    private int age;
    private double score;
    private static int a;

    public static void setA(int a){
        Student.a = a;
    }

    public static int getA(){
        return Student.a;
    }

    //现在希望外界可以访问名字,提供name的get方法
    public String getName() {
        return this.name;
    }

    //现在希望外界可以赋值名字,提供name的set方法
    public void setName(String name) {
        this.name = name;
    }

    //假如我希望外界看到我，永远18岁
    public int getAge() {
        return age;
    }

    //可以控制赋值，比如age应该在1到130
    public void setAge(int age) {
        if (age < 1 || age > 130) {
            System.out.println("您输入的年龄不合法！请重新输入！");
            return;
        }
        this.age = age;
    }

    public Student() {
    }

   /* public Student(String name, int age, double score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }*/

    public Student(String name, double score) {
        this.name = name;
        this.score = score;
    }
}
